package com.xlh.job;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.xlh.constant.ConcludeContant;
import com.xlh.dao.conclude.ext.BusiFullMarkMapperExt;
import com.xlh.dao.conclude.ext.ConcludeMapperExt;
import com.xlh.dao.conclude.helper.BusiFullMarkMapperHelper;
import com.xlh.dao.conclude.helper.ConcludeScoreMapperHelper;
import com.xlh.dao.statistic.helper.StatisticsStudentCourseMapperHelper;
import com.xlh.dao.support.helper.StatisticsMapperHelper;
import com.xlh.dto.conclude.BusiFullMarkStudentScoreDTO;
import com.xlh.dto.conclude.job.ConcludeRefSysCheckSubInfoDTO;
import com.xlh.dto.conclude.job.ConcludeSysStudentInfoDTO;
import com.xlh.enums.conclude.LikedSysFunkEnum;
import com.xlh.pojo.conclude.BusiFullMark;
import com.xlh.pojo.conclude.ConcludeScore;
import com.xlh.pojo.statistic.StatisticStudentCourse;
import com.xlh.pojo.support.Statistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author chufangzheng
 * 工程认证关联系统
 *
 *
 */
@Component
public class ConcludeRefSysTask {

    private final static Logger LOGGER = LoggerFactory.getLogger(ConcludeRefSysTask.class);

    @Autowired
    private ConcludeMapperExt concludeMapperExt;

    @Autowired
    private StatisticsStudentCourseMapperHelper studentCourseMapperHelper;

    @Autowired
    private BusiFullMarkMapperHelper busiFullMarkMapperHelper;

    @Autowired
    private BusiFullMarkMapperExt busiFullMarkMapperExt;

    @Autowired
    private StatisticsMapperHelper statisticsMapperHelper;

    @Autowired
    private ConcludeScoreMapperHelper concludeScoreMapperHelper;


    @Scheduled(cron = "0 0 2 * * *")
    public void sysDataToConclude() {

        LOGGER.info("statistic task start");
        updateToConclude(null);
        LOGGER.info("statistic task end");
    }


    @Transactional
    public void updateToConclude(Long concludeId){

        // 1. 查询出关联系统的未被删除的学生
        List<ConcludeSysStudentInfoDTO> studentIds = concludeMapperExt.findRefSysStudentInfos(concludeId);
        // 2. 查询所有关联工程认证的IDS
        List<ConcludeRefSysCheckSubInfoDTO> subIds = concludeMapperExt.findRefSysCheckSubInfos(concludeId);

        Map<String, List<ConcludeRefSysCheckSubInfoDTO>> subMapByBusiType = subIds.stream().collect(Collectors.groupingBy(ConcludeRefSysCheckSubInfoDTO::getSysFunc));

        List<ConcludeScore> updateRecords = Lists.newArrayList();
        // 1. 学生签到
        attendScoreRefConclude(studentIds, subMapByBusiType, updateRecords);
        // 2. 课堂表现
        perScoreRefConclude(studentIds, subMapByBusiType, updateRecords);
        // 3. 随堂练习
        practiceScoreRefConclude(studentIds, subMapByBusiType, updateRecords);
        // 4. 实验报告
        reportScoreRefConclude(studentIds, subMapByBusiType, updateRecords);
        // 5. 考试
        testScoreRefConclude(studentIds, subMapByBusiType, updateRecords);

        // 6. 执行插入方法
        for (ConcludeScore updateRecord : updateRecords) {

            ConcludeScore concludeScore = concludeScoreMapperHelper.findCheckSubScoreBySubIdAndSno(updateRecord.getCheckSubId(),
                    updateRecord.getStudentNo());
            if(ObjectUtil.isNull(concludeScore)){
                // 直接插入
                concludeScoreMapperHelper.insert(updateRecord);
            }else{
                // 比较更新时间靠后则进行更新
                Date scoureUpdateTime = concludeScore.getUpdateTime();
                Date newUpdateTime = updateRecord.getUpdateTime();
                if(newUpdateTime.compareTo(scoureUpdateTime) == 1){
                    concludeScore.setScore(updateRecord.getScore());
                    concludeScore.setUpdateTime(newUpdateTime);
                    concludeScoreMapperHelper.update(concludeScore);
                }
            }
        }
        // 执行更新时间方法
        concludeMapperExt.updateJobExeTime(concludeId);

    }

    /** 代码结构相似 抽取成公共方法
     * 考试更新数据
     * @param studentIds
     * @param subMapByBusiType
     * @param updateRecord
     */
    private void testScoreRefConclude(List<ConcludeSysStudentInfoDTO> studentIds,
                                      Map<String, List<ConcludeRefSysCheckSubInfoDTO>> subMapByBusiType,
                                      List<ConcludeScore> updateRecord) {

        String sysFunkKey = LikedSysFunkEnum.TEST.getSysFunkKey();
        // 1. 去static表中查询并获取比例 考勤
        List<ConcludeRefSysCheckSubInfoDTO> subInfos = subMapByBusiType.get(sysFunkKey);

        if(CollectionUtil.isEmpty(subInfos)){
            return;
        }
        // 用于缓存满分项
        for (ConcludeRefSysCheckSubInfoDTO subInfoDTO : subInfos) {

            for (ConcludeSysStudentInfoDTO studentInfo : studentIds) {
                // 目标ID需要相等
                if (!subInfoDTO.getConcludeId()
                        .equals(studentInfo.getConcludeId())) {
                    continue;
                }
                Long courseId = studentInfo.getCourseId();
                String sno = studentInfo.getSno();
                Long userId = studentInfo.getUserId();
                BusiFullMarkStudentScoreDTO testStudentAvgScore = busiFullMarkMapperExt.findTestStudentAvgScore(courseId, userId);
                // 查询满分项最大更新时间
                if (ObjectUtil.isNull(testStudentAvgScore)) {
                    continue;
                }
                // 最大更新时间的问题
                Double score = testStudentAvgScore.getScore();
                Date updateTime = testStudentAvgScore.getUpdateTime();
                ConcludeScore concludeScore = new ConcludeScore();
                concludeScore.setScore(NumberUtil.round(NumberUtil.mul(score, getFullMark(subInfoDTO.getFullMark())), ConcludeContant.RETAIN_DECIMALS) ); // 比例
                concludeScore.setCheckSubId(subInfoDTO.getSubId());
                concludeScore.setCheckId(subInfoDTO.getCheckId());
                concludeScore.setStudentNo(sno);
                concludeScore.setUpdateTime(updateTime);
                // 插入到更新记录中
                updateRecord.add(concludeScore);
            }
        }
    }

    /**
     *
     * @param studentIds
     * @param subMapByBusiType
     * @param updateRecord
     */
    private void reportScoreRefConclude(List<ConcludeSysStudentInfoDTO> studentIds, Map<String, List<ConcludeRefSysCheckSubInfoDTO>> subMapByBusiType, List<ConcludeScore> updateRecord) {
        String sysFunkKey = LikedSysFunkEnum.REPORT.getSysFunkKey();
        // 1. 去static表中查询并获取比例 考勤
        List<ConcludeRefSysCheckSubInfoDTO> subInfos = subMapByBusiType.get(sysFunkKey);

        if(CollectionUtil.isEmpty(subInfos)){
            return;
        }


        // 用于缓存满分项
        for (ConcludeRefSysCheckSubInfoDTO subInfoDTO : subInfos) {

            for (ConcludeSysStudentInfoDTO studentInfo : studentIds) {
                // 目标ID需要相等
                if (!subInfoDTO.getConcludeId()
                        .equals(studentInfo.getConcludeId())) {
                    continue;
                }
                Long classId = studentInfo.getClassId();
                Long courseId = studentInfo.getCourseId();
                String sno = studentInfo.getSno();
                Long studentId = studentInfo.getSysStuId();
                List<BusiFullMarkStudentScoreDTO> coursePracticeAvgScore = busiFullMarkMapperExt.findCourseExperimentAvgScore(courseId, sysFunkKey, classId, studentId);
                // 查询满分项最大更新时间
                Date maxUpdateTime = busiFullMarkMapperExt.findMaxReportUpdateTime(studentId, courseId, sysFunkKey);

                if (CollectionUtil.isEmpty(coursePracticeAvgScore)) {
                    continue;
                }
                BusiFullMarkStudentScoreDTO busiFullMarkStudentScoreDTO = coursePracticeAvgScore.get(0);
                Double score = busiFullMarkStudentScoreDTO.getScore();
                Date updateTime = busiFullMarkStudentScoreDTO.getUpdateTime();

                if(ObjectUtil.isNotNull(maxUpdateTime)){
                    if(maxUpdateTime.compareTo(updateTime) == 1){
                        updateTime = maxUpdateTime;
                    }
                }
                ConcludeScore concludeScore = new ConcludeScore();
                Double proportion =  Double.valueOf(NumberUtil.div(score, Double.valueOf(100d)));
                Double fullMark = Double.valueOf(getFullMark(subInfoDTO.getFullMark()));
                concludeScore.setScore( new BigDecimal(NumberUtil.mul(proportion , fullMark)) ); // 比例
                concludeScore.setCheckSubId(subInfoDTO.getSubId());
                concludeScore.setCheckId(subInfoDTO.getCheckId());
                concludeScore.setStudentNo(sno);
                concludeScore.setUpdateTime(updateTime);
                // 插入到更新记录中
                updateRecord.add(concludeScore);
            }
        }
    }

    /**
     * 随堂练习更新到工程认证
     * @param studentIds
     * @param subMapByBusiType
     * @param updateRecord
     */
    private void practiceScoreRefConclude(List<ConcludeSysStudentInfoDTO> studentIds, Map<String, List<ConcludeRefSysCheckSubInfoDTO>> subMapByBusiType, List<ConcludeScore> updateRecord) {
        String sysFunkKey = LikedSysFunkEnum.PRACTICE.getSysFunkKey();
        // 1. 去static表中查询并获取比例 考勤
        List<ConcludeRefSysCheckSubInfoDTO> subInfos = subMapByBusiType.get(sysFunkKey);

        if(CollectionUtil.isEmpty(subInfos)){
            return;
        }
        // 用于缓存满分项
        for (ConcludeRefSysCheckSubInfoDTO subInfoDTO : subInfos) {

            for (ConcludeSysStudentInfoDTO studentInfo : studentIds) {
                // 目标ID需要相等
                if (!subInfoDTO.getConcludeId()
                        .equals(studentInfo.getConcludeId())) {
                    continue;
                }
                Long classId = studentInfo.getClassId();
                Long courseId = studentInfo.getCourseId();
                String sno = studentInfo.getSno();
                Long studentId = studentInfo.getSysStuId();
                List<BusiFullMarkStudentScoreDTO> coursePracticeAvgScore = busiFullMarkMapperExt.findCoursePracticeAvgScore(courseId, sysFunkKey, classId, studentId);
                // 查询最大更新时间
                Date maxUpdateTime = busiFullMarkMapperExt.findMaxPracticeUpdateTime(studentId, courseId, sysFunkKey);

                if (CollectionUtil.isEmpty(coursePracticeAvgScore)) {
                    continue;
                }
                BusiFullMarkStudentScoreDTO busiFullMarkStudentScoreDTO = coursePracticeAvgScore.get(0);
                // 最大更新时间的问题
                Double score = busiFullMarkStudentScoreDTO.getScore();
                Date updateTime = busiFullMarkStudentScoreDTO.getUpdateTime();
                if(ObjectUtil.isNotNull(maxUpdateTime)){
                    if(maxUpdateTime.compareTo(updateTime) == 1){
                        updateTime = maxUpdateTime;
                    }
                }
                ConcludeScore concludeScore = new ConcludeScore();
                concludeScore.setScore(NumberUtil.mul(Double.valueOf(NumberUtil.div(score, Double.valueOf(100d))), getFullMark(subInfoDTO.getFullMark()))); // 比例
                concludeScore.setCheckSubId(subInfoDTO.getSubId());
                concludeScore.setCheckId(subInfoDTO.getCheckId());
                concludeScore.setStudentNo(sno);
                concludeScore.setUpdateTime(updateTime);
                // 插入到更新记录中
                updateRecord.add(concludeScore);
            }
        }
    }


    /**
     * 课堂表现
     * @param studentIds
     * @param subMapByBusiType
     * @param updateRecord
     */
    private void perScoreRefConclude(List<ConcludeSysStudentInfoDTO> studentIds, Map<String, List<ConcludeRefSysCheckSubInfoDTO>> subMapByBusiType, List<ConcludeScore> updateRecord) {
        String sysFunkKey = LikedSysFunkEnum.CLASSROOM_PERFORMANCE.getSysFunkKey();
        // 1. 去static表中查询并获取比例 考勤
        List<ConcludeRefSysCheckSubInfoDTO> performance = subMapByBusiType.get(sysFunkKey);

        if(CollectionUtil.isEmpty(performance)){
            return;
        }
        // 用于缓存满分项
        Map<String, BusiFullMark> fullMarkInfo = new HashMap<>();

        for (ConcludeRefSysCheckSubInfoDTO subInfoDTO : performance) {

            for (ConcludeSysStudentInfoDTO studentInfo : studentIds) {
                // 目标ID需要相等
                if (!subInfoDTO.getConcludeId()
                        .equals(studentInfo.getConcludeId())) {
                    continue;
                }
                Long userId = studentInfo.getUserId();
                Long classId = studentInfo.getClassId();
                Long courseId = studentInfo.getCourseId();
                String sno = studentInfo.getSno();
                StatisticStudentCourse statisticStudentCourse = studentCourseMapperHelper.getByCondition(userId, courseId, classId);
                if (ObjectUtil.isNull(statisticStudentCourse)) {
                    continue;
                }
                BusiFullMark busiFullMark = null;
                if (ObjectUtil.isNotNull(fullMarkInfo.get(sysFunkKey + courseId + classId))) {

                    busiFullMark = fullMarkInfo.get(sysFunkKey + courseId + classId);
                } else {
                    busiFullMark = busiFullMarkMapperHelper.get(sysFunkKey, courseId, classId, null);
                    fullMarkInfo.put(sysFunkKey + courseId + classId, busiFullMark);
                }
                Integer score = statisticStudentCourse.getManifestScore();
                // 无分数情况
                if(score == null){
                    continue;
                }
                if (score < 0) {
                    score = 0;
                }
                Date updateTime = busiFullMark.getUpdateTime();
                if (statisticStudentCourse.getUpdateTime().compareTo(updateTime) == 1) {
                    updateTime = statisticStudentCourse.getUpdateTime();
                }
                ConcludeScore concludeScore = new ConcludeScore();
                concludeScore.setScore(NumberUtil.mul(NumberUtil.div(score, busiFullMark.getFullMark()), getFullMark(subInfoDTO.getFullMark()))); // 比例
                concludeScore.setCheckSubId(subInfoDTO.getSubId());
                concludeScore.setCheckId(subInfoDTO.getCheckId());
                concludeScore.setStudentNo(sno);
                concludeScore.setUpdateTime(updateTime);
                // 插入到更新记录中
                updateRecord.add(concludeScore);
            }
        }
    }

    /**
     * 签到的平时成绩更新到工程认证
     * @param studentIds
     * @param subMapByBusiType
     * @param updateRecord
     */
    private void attendScoreRefConclude(List<ConcludeSysStudentInfoDTO> studentIds, Map<String, List<ConcludeRefSysCheckSubInfoDTO>> subMapByBusiType, List<ConcludeScore> updateRecord) {
        // 1. 查询考勤系统的成绩信息
        String sysFunkKey = LikedSysFunkEnum.CHECKING_IN.getSysFunkKey();

        // 1. 去static表中查询并获取比例 考勤
        List<ConcludeRefSysCheckSubInfoDTO> attendance = subMapByBusiType.get(sysFunkKey);

        if(CollectionUtil.isEmpty(attendance)){
            return;
        }
        // 用于缓存满分项
        Map<String, BusiFullMark> fullMarkInfo = new HashMap<>();

        for (ConcludeRefSysCheckSubInfoDTO subInfoDTO : attendance) {

            for (ConcludeSysStudentInfoDTO studentInfo : studentIds) {
                // 目标ID需要相等
                if(!subInfoDTO.getConcludeId()
                        .equals(studentInfo.getConcludeId())){
                    continue;
                }
                Long userId = studentInfo.getUserId();
                Long classId = studentInfo.getClassId();
                Long courseId = studentInfo.getCourseId();
                String sno = studentInfo.getSno();
                List<Statistics> attendanceRecord = statisticsMapperHelper.findByCondition(userId, courseId, classId);


                BusiFullMark busiFullMark = null;
                if(ObjectUtil.isNotNull(fullMarkInfo.get(sysFunkKey+courseId+classId))){

                    busiFullMark = fullMarkInfo.get(sysFunkKey + courseId + classId);
                }else{
                    busiFullMark = busiFullMarkMapperHelper.get(sysFunkKey, courseId, classId, null);
                    fullMarkInfo.put(sysFunkKey+courseId+classId, busiFullMark);
                }
                if(ObjectUtil.isNull(busiFullMark.getDegression())){
                    continue;
                }
                Statistics statistics = null;

                if(CollectionUtil.isEmpty(attendanceRecord)){

                    statistics = new Statistics();
                    statistics.setTruantNo(0);
                    statistics.setUpdateTime(busiFullMark.getUpdateTime());
                }else{
                    statistics = attendanceRecord.get(0);
                }

                Integer score = busiFullMark.getFullMark() - (statistics.getTruantNo() * busiFullMark.getDegression());
                if(score < 0){
                    score = 0;
                }
                Date updateTime = busiFullMark.getUpdateTime();
                Console.log("------满分项更新时间------" + DateUtil.format(updateTime, DatePattern.NORM_DATETIME_PATTERN));
                Console.log("------记录更新时间---------" + DateUtil.format(statistics.getUpdateTime(), DatePattern.NORM_DATETIME_PATTERN));

                if(statistics.getUpdateTime().compareTo(updateTime)==1){
                    updateTime = statistics.getUpdateTime();
                }
                ConcludeScore concludeScore = new ConcludeScore();
                concludeScore.setScore(NumberUtil.mul(NumberUtil.div(score, busiFullMark.getFullMark()), getFullMark(subInfoDTO.getFullMark()))); // 比例
                concludeScore.setCheckSubId(subInfoDTO.getSubId());
                concludeScore.setCheckId(subInfoDTO.getCheckId());
                concludeScore.setStudentNo(sno);
                concludeScore.setUpdateTime(updateTime);
                // 插入到更新记录中
                updateRecord.add(concludeScore);
            }

        }
    }


    /**
     * 获取满分分值
     * @param fullMark
     * @return
     */
    public Integer getFullMark(Integer fullMark){

        if(ObjectUtil.isNull(fullMark)){

            return 100;
        }else{

            return fullMark;
        }
    }






}
